package com.candy.biz.manager;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.candy.biz.domain.dto.SysUserDTO;
import com.candy.biz.domain.entity.SysDept;
import com.candy.biz.domain.entity.SysUser;
import com.candy.biz.domain.param.SysUserSaveParam;
import com.candy.biz.domain.vo.SysUserVO;
import com.candy.biz.mapper.SysUserMapper;
import com.candy.common.domain.PageVO;
import com.candy.common.enums.AdminErrorEnum;
import com.candy.common.enums.RedisKeyEnum;
import com.candy.common.manager.RedisManager;
import com.candy.common.utils.Assert;
import com.candy.common.utils.CommonUtil;
import com.mybatisflex.core.paginate.Page;
import jakarta.annotation.PostConstruct;
import lombok.AllArgsConstructor;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.candy.biz.domain.entity.table.SysUserTableDef.SYS_USER;

/**
 * @author rong xi
 * @version 1.0
 * @date 2023/09/18 23:48
 */
@Component
@AllArgsConstructor
@Slf4j
public class SysUserManager {

    private final SysUserMapper sysUserMapper;
    private static SysUserManager manager;

    @PostConstruct
    private void init(){
        manager = this;
    }

    /**
     * 分页对象转换分页数据
     * @param page 分页结果
     * @return 分页数据
     */
    public static PageVO<SysUserVO> pageToPageVO(Page<SysUser> page) {
        //转换处理
        return PageVO.of(posToVos(page.getRecords()),page.getTotalRow());
    }

    /**
     * 创建用户准备
     * @param param 创建参数
     * @return po对象
     */
    public static SysUser insertPrepare(SysUserSaveParam param){
        SysUser sysUser = BeanUtil.copyProperties(param, SysUser.class);
        //判断用户是否存在
        long count = manager.sysUserMapper.selectCountByCondition(SYS_USER.LOGIN_ACCOUNT.eq(sysUser.getLoginAccount()));
        Assert.isTrue(count == 0,AdminErrorEnum.USER_ALREADY_EXISTS);

        sysUser.setId(IdUtil.getSnowflakeNextId());
        sysUser.setCreateUser(StpUtil.getLoginIdAsLong());
        sysUser.setCreateTime(LocalDateTime.now());
        //生成8个随机字符串
        sysUser.setSalt(RandomUtil.randomString(8));
        //密码加密 简单的MD5吧
        sysUser.setLoginPassword(genPassword(sysUser.getLoginPassword(),sysUser.getSalt()));
        return sysUser;
    }

    /**
     * 修改用户准备
     * @param param 修改参数
     * @return po对象
     */
    public static SysUser updatePrepare(SysUserSaveParam param){
        SysUser sysUser = BeanUtil.copyProperties(param, SysUser.class);
        sysUser.setLoginAccount(null);
        sysUser.setLoginPassword(null);
        sysUser.setUpdateUser(StpUtil.getLoginIdAsLong());
        sysUser.setUpdateTime(LocalDateTime.now());
        return sysUser;
    }

    /**
     * 参数转持久化对象
     */
    public static SysUser paramToPo(SysUserSaveParam param){
        return BeanUtil.copyProperties(param, SysUser.class);
    }

    /**
     * PO对象转VO对象
     * @param po po对象
     * @return vo对象
     */
    public static SysUserVO poToVo(SysUser po){
        SysUserVO convert = CommonManager.convert(po, SysUserVO.class);
        convert.setDeptName(SysDeptManager.getDept(convert.getDeptId()).map(SysDept::getDeptName).orElse(""));
        return convert;
    }

    /**
     * po集合转vo集合
     * @param pos po集合对象
     * @return vos vo集合对象
     */
    public static List<SysUserVO> posToVos(List<SysUser> pos){
        List<SysUserVO> convert = CommonManager.convert(pos, SysUserVO.class);
        List<Long> deptIds = pos.stream().map(SysUser::getDeptId).collect(Collectors.toList());
        Optional<Map<Long, SysDept>> sysDeptMapOpt = SysDeptManager.getDeptMap(deptIds);
        for (SysUserVO sysUserVO : convert) {
            sysUserVO.setDeptName(sysDeptMapOpt.map(m->m.get(sysUserVO.getDeptId())).map(SysDept::getDeptName).orElse(""));
        }
        return convert;
    }

    /**
     * 生成密码
     * @param originalPassword 原始明文密码
     * @param salt 密码盐
     * @return 密码
     */
    public static String genPassword(String originalPassword,String salt){
        return DigestUtil.md5Hex(salt+originalPassword);
    }

    /**
     * 根据id查询用户信息
     *
     * @param id 用户id
     * @return 用户信息
     */
    public static SysUserDTO getUserInfo(@NonNull Long id){
        return getUserInfoOpt(id).orElse(null);
    }

    /**
     * 根据id查询用户信息
     *
     * @param id 用户id
     * @return 用户信息
     */
    public static Optional<SysUserDTO> getUserInfoOpt(Long id){
        return CommonUtil.predicateFunction(id,
                ObjectUtil::isNull,
                (i)->Optional.empty(),
                (d)-> RedisManager.<SysUserDTO>getOpt(id)
                            .or(()->Optional.ofNullable(manager.sysUserMapper.selectOneById(id))
                                    .map(e -> {
                                        SysUserDTO sysUserDTO = BeanUtil.copyProperties(e, SysUserDTO.class);
                                        RedisManager.setValue(RedisKeyEnum.USER_INFO.getKey(id), sysUserDTO, RedisKeyEnum.USER_INFO.getTimeout());
                                        return sysUserDTO;
                                    }))
                );
    }


    /**
     * 根据id集合查询用户缓存信息
     *
     * @param idList id集合
     * @return 用户信息map
     */
    public static Map<Long,SysUserDTO> getUserInfoMap(@NonNull List<Long> idList){
        return getUserInfoMapOpt(idList).orElseGet(HashMap::new);
    }

    /**
     * 根据id集合查询用户缓存信息
     *
     * @param idList id集合
     * @return 用户信息map
     */
    public static Optional<Map<Long,SysUserDTO>> getUserInfoMapOpt(List<Long> idList){
        return CommonUtil.predicateFunction(idList,
                CollectionUtil::isEmpty,
                (l)->Optional.empty(),
                (l)->Optional.ofNullable(manager.sysUserMapper.selectListByIds(idList))
                            .map(e -> BeanUtil.copyToList(e, SysUserDTO.class).stream().collect(Collectors.toMap(SysUserDTO::getId, Function.identity())))
        );
    }
}
